﻿using System;
using System.Text;
using System.Linq.Expressions;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace NEmu
{
    public static class Tools
    {
        public static ushort Create16(byte high, byte low)
        {
            return (ushort)((ushort)high << 8 | low);
        }

        public static uint Create32(byte a, byte b, byte c, byte d)
        {
            return (uint)((a << 24) | (b << 16) | (c << 8) | d);
        }

        public readonly static Func<ushort, ushort> ByteSwap = (ushort a) => {
            return (ushort)((a << 8) | (a >> 8));
        };

        public static string PrintBits(byte value)
        {
            string a = "";
            a += ((value >> 7) & 0x1).ToString();
            a += ((value >> 6) & 0x1).ToString();
            a += ((value >> 5) & 0x1).ToString();
            a += ((value >> 4) & 0x1).ToString();
            a += ((value >> 3) & 0x1).ToString();
            a += ((value >> 2) & 0x1).ToString();
            a += ((value >> 1) & 0x1).ToString();
            a += (value        & 0x1).ToString();
            return a;
        }

        public static TStruct FillStruct<TStruct>(Stream source) where TStruct : struct
        {
            TStruct theStruct;

            if (source == null)
                throw new NullReferenceException("source is null!");

            if (!source.CanRead)
                throw new ArgumentException("can't read source!");

            source.Position = 0;
            byte[] buffer = new byte[Marshal.SizeOf(typeof(TStruct))];
            source.Read(buffer, 0, buffer.Length);
            GCHandle hBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            theStruct = (TStruct)Marshal.PtrToStructure(hBuffer.AddrOfPinnedObject(), typeof(TStruct));
            hBuffer.Free();
            return theStruct;
        }

        public static object[] GetEnumAttributes<TEnum>(TEnum enumValue, Type attributeType) where TEnum : struct, IConvertible
        {
            if (!typeof(TEnum).IsEnum)
                throw new ArgumentException("TEnum is not a enumeration type!");

            if (attributeType != typeof(Attribute))
                throw new ArgumentException("attributeType is not an attribute type!");

            return enumValue.GetType().GetField(enumValue.ToString()).GetCustomAttributes(attributeType, false);
        }

        public static void InitUnmanagedStructure<TStruct>(IntPtr structPtr) where TStruct : struct
        {
            for (int i = 0; i < Marshal.SizeOf(typeof(TStruct)); i++)
            {
                Marshal.WriteByte(structPtr, i, 0);
            }
        }

        public static IntPtr AllocateUnmanagedStructure<TStruct>() where TStruct : struct
        {
            IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(TStruct)));
            InitUnmanagedStructure<TStruct>(ptr);
            return ptr;
        }
    }
}
